package cn.tedu.bece.front.common.service;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.apistd.uni.Uni;
import com.apistd.uni.UniException;
import com.apistd.uni.UniResponse;
import com.apistd.uni.sms.UniMessage;
import com.apistd.uni.sms.UniSMS;
import cn.tedu.bece.front.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class SmsService {

    @Value("${app.sms.access-key-id}")
    public String accessKeyId;

    @Value("${app.sms.access-key-secret}")
    private String accessKeySecret;

    @Value("${app.sms.signature}")
    private String signature;

    @Value("${app.sms.template-id}")
    private String templateId;

    @Value("${app.sms.ttl}")
    private long ttl;

    public static final String SMS_CACHE_KEY = "sms:";

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @PostConstruct
    public void init() {
        // 初始化，若使用简易验签模式仅传入第一个参数即可
        Uni.init(accessKeyId, accessKeySecret);
    }

    /**
     * 发送短信验证码
     *
     * @param phone 手机号
     */
    public void send(String phone) {
        // 判断是否在120秒内发送过验证码
        Long expire = redisTemplate.getExpire(SMS_CACHE_KEY + phone);
        if (expire != null && (ttl - expire) < 120) {
            throw new ServiceException("请勿频繁发送");
        }

        // 生成短信验证码
        String code = RandomUtil.randomNumbers(4);

        // 设置自定义参数 (变量短信)
        Map<String, String> templateData = new HashMap<>();
        templateData.put("code", code);
        templateData.put("ttl", String.valueOf(ttl / 60));

        // 构建信息
        UniMessage message = UniSMS.buildMessage()
                .setTo(phone)
                .setSignature(signature)
                .setTemplateId(templateId)
                .setTemplateData(templateData);

        // 发送短信
        try {
            UniResponse res = message.send();
            log.debug("发送短信结果: {}", res);
            if ("0".equals(res.code)) {
                redisTemplate.opsForValue().set(SMS_CACHE_KEY + phone, code, ttl, TimeUnit.SECONDS);
            } else {
                throw new ServiceException(res.message);
            }
        } catch (UniException e) {
            log.error("发送短信失败, code: {}, message: {}", e.code, e.message);
            throw new ServiceException("发送短信失败，请稍后再尝试");
        }
    }

    /**
     * 校验短信验证码
     *
     * @param phone 手机号
     * @param code  验证码
     */
    public void check(String phone, String code) {
        if (StrUtil.isEmpty(phone))
            throw new ServiceException("手机号不能为空");

        if (StrUtil.isEmpty(code))
            throw new ServiceException("验证码不能为空");

        Object cacheCode = redisTemplate.opsForValue().get(SMS_CACHE_KEY + phone);

        if (cacheCode == null)
            throw new ServiceException("验证码已过期");

        if (!code.equals(cacheCode))
            throw new ServiceException("验证码错误");

        redisTemplate.delete(SMS_CACHE_KEY + phone);
    }

}
